package com.moli.iov.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 *
 * </p>
 *
 * @author zql
 * @since 2019/9/24 16:50
 */
public class JwtTokenUtil {
  private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);
  private static final String CLAIM_KEY_USERNAME = "sub";
  private static final String CLAIM_KEY_CREATED = "created";

  /**
   * 根据负责生成JWT的token
   */
  private static String generateToken(Map<String, Object> claims, String salt, Long expirationTime) {
    return Jwts.builder()
        .setClaims(claims)
        .setExpiration(generateExpirationDate(expirationTime))
        .signWith(SignatureAlgorithm.HS512, salt)
        .compact();
  }

  /**
   * 从token中获取JWT中的负载
   */
  private static Claims getClaimsFromToken(String token, String salt) {
    Claims claims = null;
    try {
      claims = Jwts.parser()
          .setSigningKey(salt)
          .parseClaimsJws(token)
          .getBody();
    } catch (Exception e) {
      LOGGER.info("JWT格式验证失败:{}",token);
    }
    return claims;
  }

  /**
   * 生成token的过期时间
   */
  private static   Date generateExpirationDate(Long expirationTime) {
    return new Date(System.currentTimeMillis() + expirationTime * 1000);
  }

  /**
   * 从token中获取登录用户名
   */
  public static String getUserNameFromToken(String token, String salt) {
    String username = "";
    try {
      Claims claims = getClaimsFromToken(token, salt);
      username =  claims.getSubject();
    } catch (Exception e) {
      LOGGER.error("无效token: {}", token);
    }
    return username;
  }

  /**
   * 验证token是否还有效
   *
   * @param token       客户端传入的token
   * @param username 从数据库中查询出来的用户信息
   */
  public static boolean validateToken(String token, String salt, String username) {
    String uname = getUserNameFromToken(token, salt);
    return uname.equals(username) && !isTokenExpired(token, salt);
  }

  /**
   * 判断token是否已经失效
   */
  private static boolean isTokenExpired(String token, String salt) {
    Date expiredDate = getExpiredDateFromToken(token, salt);
    return expiredDate.before(new Date());
  }

  /**
   * 从token中获取过期时间
   */
  private static Date getExpiredDateFromToken(String token, String salt) {
    Claims claims = getClaimsFromToken(token, salt);
    return claims.getExpiration();
  }

  /**
   * 根据用户信息生成token
   */
  public static String generateToken(String username, String salt, Long expirationTime) {
    Map<String, Object> claims = new HashMap<>();
    claims.put(CLAIM_KEY_USERNAME, username);
    claims.put(CLAIM_KEY_CREATED, new Date());
    return generateToken(claims, salt, expirationTime);
  }

  /**
   * 判断token是否可以被刷新
   */
  public static boolean canRefresh(String token, String salt) {
    return !isTokenExpired(token, salt);
  }

  /**
   * 刷新token
   */
  public static String refreshToken(String token, String salt, Long expirationTime) {
    Claims claims = getClaimsFromToken(token, salt);
    claims.put(CLAIM_KEY_CREATED, new Date());
    return generateToken(claims, salt, expirationTime);
  }
}
